﻿using System;
using System.Collections.Generic;
using System.Text;
using VideoLink.Frames;
using System.Drawing;

namespace VideoLink.Streams
{
    /// <summary>
    /// Приёмник видео, принимает видео в виде последовательности
    /// экзмпляров класса Bitmap и воспроизводит их с частотой 25 кадров в секунду
    /// </summary>
    public class ByFrameJPEGReceiver : VideoReceiverBase
    {
        #region Fields

        /// <summary>
        /// Очередь кадров, сюда помещается кадр при получении
        /// и удаляется отсюда при воспроизведении
        /// </summary>
        private Queue<VideoStreamState> framesQueue;

        /// <summary>
        /// Таймер, по которому обновляется  изображение
        /// </summary>
        private System.Windows.Forms.Timer updateTimer;
        /// <summary>
        /// Требование дизайнера
        /// </summary>
        private System.ComponentModel.IContainer components;
        /// <summary>
        /// Контрол, на котором рисуются кадры
        /// </summary>
        protected Canvas canvas;
        
        #endregion

        /// <summary>
        /// Создать новый экземпляр класса с указанным ID потока
        /// </summary>
        /// <param name="streamID">
        /// ID потока, уникален для каждого потока
        /// </param>
        public ByFrameJPEGReceiver(int streamID)
            : base(streamID)
        {
            framesQueue = new Queue<VideoStreamState>();
            InitializeComponent();
            InitCanvas();
        }

        /// <summary>
        /// Создать новый экземпляр класса по полученной информации о потоке
        /// </summary>
        /// <param name="stream">
        /// Информация о потоке, который будет приниматься данным экземпляром
        /// </param>
        public ByFrameJPEGReceiver(VideoStreamInfo stream)
            : this(stream.StreamID)
        {
        }

        /// <summary>
        /// Обработать новый, только что полученный, кадр.
        /// Данная реализация ставит кадр в очередь.
        /// </summary>
        /// <param name="frame">Кадр</param>
        public override void NewFrameReceived(VideoStreamState frame)
        {
            base.NewFrameReceived(frame);

            framesQueue.Enqueue(frame);
            updateTimer.Enabled = true;
        }

        #region Component

        /// <summary>
        /// Дизайнер
        /// </summary>
        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            this.updateTimer = new System.Windows.Forms.Timer(this.components);
            this.SuspendLayout();
            // 
            // updateTimer
            // 
            this.updateTimer.Interval = 40;
            this.updateTimer.Tick += new System.EventHandler(this.updateTimer_Tick);
            // 
            // ByFrameJPEGReceiver
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.Name = "ByFrameJPEGReceiver";
            this.ResumeLayout(false);

        }

        /// <summary>
        /// Создать компонент, на котором будем рисовать
        /// </summary>
        private void InitCanvas()
        {
            canvas = new Canvas();
            ViewportPanel.Controls.Add(canvas);
            canvas.Dock = System.Windows.Forms.DockStyle.Fill;
        }
        
        #endregion

        /// <summary>
        /// Обработчик события таймера.
        /// Обновляется картинка. Старый кадр из очереди удаляется,
        /// а рисуется - следующий (Queue.Peek).
        /// </summary>
        /// <param name="sender">-</param>
        /// <param name="e">-</param>
        private void updateTimer_Tick(object sender, EventArgs e)
        {
            if (framesQueue.Count > 0)
            {
                var lastFrame = framesQueue.Peek();

                switch (lastFrame.State)
                {
                    case PlaybackState.Play:
                        updateTimer.Enabled = true;
                        canvas.ImageToDraw = (lastFrame.Data as OneFrame).Image;
                        break;
                    case PlaybackState.Stop:
                        updateTimer.Enabled = false;
                        canvas.ImageToDraw = null;
                        break;
                    case PlaybackState.Pause:
                        updateTimer.Enabled = false;
                        canvas.ImageToDraw = (lastFrame.Data as OneFrame).Image;
                        break;
                }

                framesQueue.Dequeue();
            }
            else
                updateTimer.Enabled = false;
        }
    }
}
